#include "dropmanager.h"

#include <QWidget>
#include <QEvent>
#include <QDropEvent>
#include <QMimeData>
#include <mutex>

#include "widgettree.h"
#include "droppablewidget.h"
#include "pageswidget.h"
#include "dragabletab.h"
#include "tabsscrollarea.h"

static std::mutex mutex;
static DropManager* mInstance {nullptr};
static QObject* mParent{nullptr};
static int mNumbers {0};

DropManager::DropManager(QObject* parent)
    :QObject(parent)
{
}

DropManager* DropManager::GetInstance()
{
    std::lock_guard<std::mutex> lock(mutex);
    if (mInstance == nullptr) {
        mInstance = new DropManager(mParent);
    }
    return mInstance;
}

void DropManager::SetParent(QObject* parent)
{
    std::lock_guard<std::mutex> lock(mutex);
    mParent = parent;
}

void DropManager::AddDroppableWidget(DroppableWidget* widget)
{
    std::lock_guard<std::mutex> lock(mutex);
    widget->SetId(mNumbers++);
    mWidgets[widget->Id()] = widget;
}

void DropManager::RemoveDroppableWidget(DroppableWidget* widget)
{
    std::lock_guard<std::mutex> lock(mutex);
    mWidgets.remove(widget->Id());
}

std::pair<DragableTab*, QWidget*> DropManager::FindSinglePage(int widgetId, int pagesWidgetId, int tabId) const
{
    std::lock_guard<std::mutex> lock(mutex);
    const auto droppableWidget = mWidgets.value(widgetId, nullptr);
    if (droppableWidget == nullptr) {
        return std::pair(nullptr, nullptr);
    }

    const auto pagesWidget = droppableWidget->FindPagesById(pagesWidgetId);
    if (pagesWidget == nullptr) {
        return std::pair(nullptr, nullptr);
    }
    auto page = pagesWidget->GetTabsScrollArea()->Page(tabId);
    return page;
}

PagesWidget* DropManager::FindPagesWidget(int widgetId, int pagesWidgetId) const
{
    std::lock_guard<std::mutex> lock(mutex);
    const auto droppableWidget = mWidgets.value(widgetId, nullptr);
    if (droppableWidget == nullptr) {
        return nullptr;
    }

    return droppableWidget->FindPagesById(pagesWidgetId);
}

bool DropManager::FilterSinglePageDrop(QObject *watched, QDropEvent *dropEvent, const std::tuple<int, int, int>& dragIndex)
{
    // qDebug() << "DropManager::eventFilter, QEvent::Drop," << mimeData->data("application/tab-data");
    if (const auto droppableWidget = qobject_cast<DroppableWidget*>(watched)) {
        qDebug() << "DropManager::eventFilter, droppableWidget";
        auto dropPos = droppableWidget->mapToGlobal(dropEvent->position().toPoint());
        return droppableWidget->PagesDropIn(dropPos, dragIndex);;
    }

    // 这个pagesWidget 主要就是这个scrollArea，需要重载一下
    const auto viewPort = qobject_cast<QWidget*>(watched);
    if (viewPort != nullptr && qobject_cast<TabsScrollArea*>(viewPort->parentWidget())) {
        const auto tabsScrollArea = qobject_cast<TabsScrollArea*>(viewPort->parentWidget());
        qDebug() << "DropManager::eventFilter, TabsScrollArea";
        auto dropPos = tabsScrollArea->mapToGlobal(dropEvent->position().toPoint());
        return tabsScrollArea->SinglePageDropIn(dropPos, dragIndex, std::make_tuple(tabsScrollArea->Id().first, tabsScrollArea->Id().second, -1));;
    }

    if (const auto dropTab = qobject_cast<DragableTab*>(watched)) {
        qDebug() << "DropManager::eventFilter, DragableTab";
        const auto dropIndex = dropTab->GetIndex();
        if (std::get<0>(dropIndex) == std::get<0>(dragIndex)
            && std::get<1>(dropIndex) == std::get<1>(dragIndex) && std::get<2>(dropIndex) == std::get<2>(dragIndex)) {
            return false;
        }
        auto dropPos = dropTab->mapToGlobal(dropEvent->position().toPoint());

        // 这里把pagesWidget找到即可
        const auto tabsScrollArea = dropTab->GetTabsScrollArea();
        if (tabsScrollArea == nullptr) {
            return false;
        }
        return tabsScrollArea->SinglePageDropIn(dropPos, dragIndex, dropIndex);;
    }
    return false;
}

bool DropManager::FilterPagesDrop(QObject *watched, QDropEvent *dropEvent, const std::pair<int, int>& dragIndex)
{
    if (const auto droppableWidget = qobject_cast<DroppableWidget*>(watched)) {
        qDebug() << "DropManager::eventFilter, droppableWidget";
        auto dropPos = droppableWidget->mapToGlobal(dropEvent->position().toPoint());
        return droppableWidget->PagesDropIn(dropPos, std::make_tuple(dragIndex.first, dragIndex.second, -1));
    }

    // 这个pagesWidget 主要就是这个scrollArea，需要重载一下
    const auto viewPort = qobject_cast<QWidget*>(watched);
    if (viewPort != nullptr && qobject_cast<TabsScrollArea*>(viewPort->parentWidget())) {
        const auto tabsScrollArea = qobject_cast<TabsScrollArea*>(viewPort->parentWidget());
        qDebug() << "DropManager::eventFilter, TabsScrollArea";
        auto dropPos = tabsScrollArea->mapToGlobal(dropEvent->position().toPoint());
        return tabsScrollArea->PagesDropIn(dropPos, dragIndex, std::make_tuple(tabsScrollArea->Id().first, tabsScrollArea->Id().second, -1));
    }

    if (const auto dropTab = qobject_cast<DragableTab*>(watched)) {
        qDebug() << "DropManager::eventFilter, DragableTab";
        const auto dropIndex = dropTab->GetIndex();
        // 如果 拖拽和拖入的页面相同，则return
        if (dragIndex.first == std::get<0>(dropIndex) && dragIndex.second == std::get<1>(dropIndex)) {
            return false;
        }
        auto dropPos = dropTab->mapToGlobal(dropEvent->position().toPoint());

        // 这里把pagesWidget找到即可
        const auto tabsScrollArea = dropTab->GetTabsScrollArea();
        if (tabsScrollArea == nullptr) {
            return false;
        }
        return tabsScrollArea->PagesDropIn(dropPos, dragIndex, dropIndex);;
    }

    return false;
}

bool DropManager::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() != QEvent::Drop) {
        return QObject::eventFilter(watched, event);
    }
    qDebug() << "DropManager::eventFilter, QEvent::Drop";
    auto dropEvent = dynamic_cast<QDropEvent*>(event);
    const auto mimeData = dropEvent->mimeData();
    if (mimeData->hasFormat("application/tab-data")) {
        qDebug() << "DropManager::eventFilter, QEvent::Drop, tab-data, " << mimeData->data("application/tab-data");
        auto array = mimeData->data("application/tab-data").split(',');
        // std::tuple<int, int, int> mIndex -> <dWidget, dPages, dTab>
        auto dragIndex = std::make_tuple(array.at(0).toInt(), array.at(1).toInt(), array.at(2).toInt());
        if (FilterSinglePageDrop(watched, dropEvent, dragIndex)) {
            dropEvent->setDropAction(Qt::MoveAction);
            dropEvent->accept();
            return true;
        }
    }

    if (mimeData->hasFormat("application/tabsScrollArea-data")) {
        qDebug() << "DropManager::eventFilter, QEvent::Drop, tabsScrollArea-data, " << mimeData->data("application/tabsScrollArea-data");
        auto array = mimeData->data("application/tabsScrollArea-data").split(',');
        auto dragIndex = std::make_pair<int, int>(array.at(0).toInt(), array.at(1).toInt());
        if (FilterPagesDrop(watched, dropEvent, dragIndex)) {
            dropEvent->setDropAction(Qt::MoveAction);
            dropEvent->accept();
            return true;
        }
    }
    dropEvent->setDropAction(Qt::IgnoreAction);
    dropEvent->ignore();
    return QObject::eventFilter(watched, event);
}
